/*
    Shader PositionTexturedAmbientDiffuseSpecular
*/    

//Matrices
float4x4 WorldViewProj : WorldViewProjection;
float4x4 World : World;
float4x4 ViewInverse : ViewInverse;

//Lumières
float4 LightPosition[5] : Position
<
    string UIName = "Light Position";
    string Object = "PointLight";
> = {   {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
};

float4 AmbientColor : Ambient 
<
    string UIName = "Ambient Color";
    string UIWidget = "Color";
> = {1, 1, 1, 0.4};

float4 DiffuseColor[5] : Diffuse
<
    string UIName = "Diffuse Color";
    string Object = "PointLight";
> = {   {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
};

float4 SpecularColor[5] : Specular
<
    string UIName = "Specular Color";
    string Object = "PointLight";
> = {   {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
};

float SpecExpon[5]
<
	string UIWidget = "slider";
	float UIMin = 1.0;
	float UIMax = 1024;
	float UIStep = 1.0;
	string UIName =  "Specular Power";
> = {512.0f, 512.0f, 512.0f, 512.0f, 512.0f};    

float LightFallOffLimit1[5]
<   
    string UIWidget = "slider";
    float UIMin = 0.1;
    float UIMax = 100.0;
    float UIStep = 1.0;
    string UIName = "Light FallOff 1";
> = {10.0, 10.0, 10.0, 10.0, 10.0};

float LightFallOffLimit2[5]
<
    string UIWidget = "slider";
    float UIMin = 0.1;
    float UIMax = 100.0;
    float UIStep = 1.0;
    string UIName = "Light FallOff 2";
> = {20.0, 20.0, 20.0, 20.0, 20.0}; 

//Textures
#ifndef TEXTURED_SURFACE

Texture coloredTexture : Diffuse
<
    string ResourceType = "2D";
    string UIName = "Texture";
>;

sampler coloredTextureSampler = sampler_state{
            texture = <coloredTexture>;
            magfilter = LINEAR;
            minfilter = LINEAR;
            mipfilter = LINEAR;
            };    
            
Texture normalTexture : Normal
<
    string ResourceType = "2D";
    string UIName = "Texture normales";
>;

sampler normalTextureSampler = sampler_state{
            texture = <normalTexture>;
            magfilter = LINEAR;
            minfilter = LINEAR;
            mipfilter = LINEAR;
};
#endif

//Fonctions diverses
float norme(float3 vecteur){
    return sqrt( pow(vecteur.x, 2) + pow(vecteur.y, 2) + pow(vecteur.z, 2));
}

//Structures de données
//Entrée dans le shader
struct AppData{
    float4 position : POSITION;
    float2 texCoordinates : TEXCOORD0;  
    
    float3 normal : NORMAL0;
};

//Sortie du vertexShader
struct VertexOutput{
    float4 position : POSITION;
    float2 texCoordinates : TEXCOORD0;
    
    float3 wP : TEXCOORD1;          //Position World       
    float3 wN : TEXCOORD2;          //Normales world    
    float3 wV : TEXCOORD3;          //View world
};


//Vertex shader
VertexOutput mainVS(AppData input){

    //Données de retour
    VertexOutput output = (VertexOutput)0;
    
    output.position = mul(input.position, (float4x4) WorldViewProj);
    output.texCoordinates = input.texCoordinates;
    
    output.wP = mul(input.position, World);
    output.wN = mul(input.normal, (float3x3) World);
    output.wV = ViewInverse[3].xyz - output.wP;
    
    return output;
}

float4 mainPS(VertexOutput input, uniform int numLight) : COLOR0 {
    float4 output = 0;
    
    //Calcul des variables utiles
    float3 wP = input.wP;    //Position monde du vertex 
    float3 wN = normalize(input.wN);      //Normale monde
    float3 wV = normalize(input.wV);
    float3 wLd = LightPosition[numLight].xyz - wP;
    float3 wL = normalize(wLd);    //Vecteur vertex-lumière    
    float3 Hn = normalize(wV + wL);  //Vecteur caméra + direction lumière
    
    //Couleur du pixel selon la texture (modifiée selon le parallax)
    float4 pixelColor = tex2D(coloredTextureSampler, input.texCoordinates);   
    
    //Calcul de l'atténuation en fonction de la distance à la lumière
    float lightPower = 1; 
    float lightDistance = norme(wLd);
    if(lightDistance <= LightFallOffLimit1[numLight])
        lightPower = 1;
    else if(lightDistance > LightFallOffLimit1[numLight] && lightDistance < LightFallOffLimit2[numLight])
        lightPower = (LightFallOffLimit2[numLight] - lightDistance) / (LightFallOffLimit2[numLight] - LightFallOffLimit1[numLight]);
    else
        lightPower = 0;
    
    //Calcul du vecteur lumière
    float4 lv = lit(    dot(wL, wN), 
                        dot(Hn, wN), 
                        SpecExpon[numLight]);
    
    //Calcul de chaque composante
    float4 ambient = AmbientColor;
    if( numLight != 0)
		ambient = float4(0, 0, 0, 0);
		
    float4 diffuse = DiffuseColor[numLight] * lv.yyyy;
    diffuse = diffuse + DiffuseColor[numLight];
    diffuse /= 2;
    float4 specular = SpecularColor[numLight] * lv.zzzz;
    
    //Calcul de l'illumination finale
    output = pixelColor * (ambient + diffuse * lightPower + specular * lightPower);
    
    //Sortie
    return output;
}

technique technique0 {
    pass p0 {
        VertexShader = compile vs_2_a mainVS();
        PixelShader = compile ps_2_a mainPS(0);
    }

    pass p1 {
        SRCBLEND = ONE;
        DESTBLEND = ONE;
        ALPHABLENDENABLE = true;
        VertexShader = compile vs_2_a mainVS();
        PixelShader = compile ps_2_a mainPS(1);
    }
    
    pass p2 {
        VertexShader = compile vs_2_a mainVS();
        PixelShader = compile ps_2_a mainPS(2);
    }
    
    pass p3 {
        VertexShader = compile vs_2_a mainVS();
        PixelShader = compile ps_2_a mainPS(3);
    }
    
    pass p4 {
        VertexShader = compile vs_2_a mainVS();
        PixelShader = compile ps_2_a mainPS(4);
    }
}


